package com.hexacta.hrs.services.employee.impl;

import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import com.hexacta.hrs.domain.employee.history.AgreementCondition;
import com.hexacta.hrs.domain.employee.history.AssignabilityStatus;
import com.hexacta.hrs.domain.employee.history.CareerRole;
import com.hexacta.hrs.domain.employee.history.EmploymentConditionHistory;
import com.hexacta.hrs.domain.employee.history.MentorAssignment;

/**
 * Ensamblador de DTOs de EmploymentConditionHistory. La informaci�n de varias
 * listas se consolida en una tabla por fecha..
 * 
 * @author jallik
 * 
 */
public class EmploymentConditionDTOAssembler {

    /**
     * Ensambla un �nico EmploymentConditionDTO con las colecciones de datos del
     * EmploymentConditionHistory especificado que resulten vigentes a una fecha
     * espec�fica. Este m�todo resulta util para localizar las condiciones de
     * empleo a una fecha particular (ej: condiciones de empleo al d�a de la
     * fecha de un empleado).
     * 
     * @param history
     *            EmploymentConditionHistory con la historia de empleo.
     * @return EmploymentConditionDTO con las condiciones de empleo a la fecha
     *         especificada.
     */
    public static EmploymentConditionDTO assembleEmploymentConditionDTO(final EmploymentConditionHistory history,
            final Date effectiveDate) {
        EmploymentConditionDTO result = new EmploymentConditionDTO();

        result.setCareerRole(history.getCareerRoles().iterator().next());

        return result;
    }

    /**
     * Ensambla el conjunto completo de EmploymentConditionDTOs resultantes de
     * la consolidaci�n de todo el EmploymentConditionHistory de un empleado.
     * 
     * @param history
     *            EmploymentConditionHistory con la historia de empleo.
     * @return List<EmploymentConditionDTO> con todas las condiciones de empleo.
     */
    public static Set<EmploymentConditionDTO> assembleEmploymentConditionsDTO(final EmploymentConditionHistory history) {

        // Se construye un TreeSet ordenable por fecha de vigencia, para
        // resolver la consolidaci�n de informaci�n en registros. La reglas es:
        // si para una fecha no se encuentra indicado un dato, corresponde el
        // dato previo que resulte m�s cercano cronol�gicamente.
        Set<EmploymentConditionDTO> result = new TreeSet<EmploymentConditionDTO>(
                new Comparator<EmploymentConditionDTO>() {
                    @Override
                    public int compare(final EmploymentConditionDTO o1, final EmploymentConditionDTO o2) {
                        return o2.getEffectiveDate().compareTo(o1.getEffectiveDate());
                    }
                });

        Map<Date, CareerRole> careerRoles = new HashMap<Date, CareerRole>();
        for (CareerRole cr : history.getCareerRoles()) {
            careerRoles.put(cr.getEffectiveDate(), cr);
        }

        Map<Date, MentorAssignment> mentorAssignments = new HashMap<Date, MentorAssignment>();
        for (MentorAssignment ma : history.getMentorAssignments()) {
            mentorAssignments.put(ma.getEffectiveDate(), ma);
        }

        Map<Date, AgreementCondition> agreementConditions = new HashMap<Date, AgreementCondition>();
        for (AgreementCondition ac : history.getAgreementConditions()) {
            agreementConditions.put(ac.getEffectiveDate(), ac);
        }

        Map<Date, AssignabilityStatus> assignabilityStatus = new HashMap<Date, AssignabilityStatus>();
        for (AssignabilityStatus as : history.getAssignabilityStatuses()) {
            assignabilityStatus.put(as.getEffectiveDate(), as);
        }

        Set<Date> dates = new TreeSet<Date>();
        dates.addAll(careerRoles.keySet());
        dates.addAll(mentorAssignments.keySet());
        dates.addAll(agreementConditions.keySet());
        dates.addAll(assignabilityStatus.keySet());

        // inicializaci�n por fechas expl�citas
        for (Date effectiveDate : dates) {
            EmploymentConditionDTO dto = new EmploymentConditionDTO();
            // debe levantar el objeto que sea vigente a la fecha
            // correspondiente.
            dto.setEffectiveDate(effectiveDate);
            dto.setCareerRole(careerRoles.get(effectiveDate));
            dto.setMentorAssignment(mentorAssignments.get(effectiveDate));
            dto.setAgreementContidion(agreementConditions.get(effectiveDate));
            dto.setAssignabilityStatus(assignabilityStatus.get(effectiveDate));
            result.add(dto);
        }

        // set de valores no especificados. completa los nulls con datos
        // anteriores que resulten vigentes.
        for (EmploymentConditionDTO dto : result) {
            if (dto.getCareerRole() == null) {
                Iterator<EmploymentConditionDTO> iter = result.iterator();
                while (iter.hasNext()) {
                    EmploymentConditionDTO innerDto = iter.next();
                    if (dto.getEffectiveDate().compareTo(innerDto.getEffectiveDate()) > 0
                            && innerDto.getCareerRole() != null) {
                        dto.setCareerRole(innerDto.getCareerRole());
                        break;
                    }
                }
            }
            if (dto.getMentorAssignment() == null) {
                Iterator<EmploymentConditionDTO> iter = result.iterator();
                while (iter.hasNext()) {
                    EmploymentConditionDTO innerDto = iter.next();
                    if (dto.getEffectiveDate().compareTo(innerDto.getEffectiveDate()) > 0
                            && innerDto.getMentorAssignment() != null) {
                        dto.setMentorAssignment(innerDto.getMentorAssignment());
                        break;
                    }
                }
            }
            if (dto.getAgreementContidion() == null) {
                Iterator<EmploymentConditionDTO> iter = result.iterator();
                while (iter.hasNext()) {
                    EmploymentConditionDTO innerDto = iter.next();
                    if (dto.getEffectiveDate().compareTo(innerDto.getEffectiveDate()) > 0
                            && innerDto.getAgreementContidion() != null) {
                        dto.setAgreementContidion(innerDto.getAgreementContidion());
                        break;
                    }
                }
            }
            if (dto.getAssignabilityStatus() == null) {
                Iterator<EmploymentConditionDTO> iter = result.iterator();
                while (iter.hasNext()) {
                    EmploymentConditionDTO innerDto = iter.next();
                    if (dto.getEffectiveDate().compareTo(innerDto.getEffectiveDate()) > 0
                            && innerDto.getAssignabilityStatus() != null) {
                        dto.setAssignabilityStatus(innerDto.getAssignabilityStatus());
                        break;
                    }
                }
            }
        }

        return result;
    }

}
